///////////////////////////////////////////////////////////////////////////////
//	FILENAME:	eTSlide.m 
//	SUMMARY:	Implementation of slide-show annotations to eText documents
//	SUPERCLASS:	Object
//	INTERFACE:	None
//	PROTOCOLS:	<DocNotification, Annotation, Tool, ASCIISupport>
//	AUTHOR:		Rohit Khare
//	COPYRIGHT:	(c) 1994 California Institure of Technology, eText Project
///////////////////////////////////////////////////////////////////////////////
//	DESCRIPTION
//		counter = an integer, initially 0
//		theImage = initially 0.tiff or 0.eps
//	on click: play counter.snd if it exists; wait; counter++; display new image
//	on cmd-click: counter--; display; play;
///////////////////////////////////////////////////////////////////////////////
//	HISTORY
//	03/10/94:	Created. Influenced by the design of eTImage.
///////////////////////////////////////////////////////////////////////////////

#import "eTSlide.h"
#define	_eTSlideVERSION	10

@implementation eTSlide
+ toolAwake:theApp
{
	char        buf[MAXPATHLEN];
	NXBundle	*bundle;
	NXImage		*theIcon;
	
	bundle = [NXBundle bundleForClass:[eTSlide class]];
	if ( [bundle getPath:buf forResource:"eTSlideIcon" ofType:"tiff"] ) {
		theIcon = [[NXImage alloc] initFromFile:buf];
		[theIcon setName:"eTSlideIcon"];
	} else {
		NXLogError("Image not found: eTSlideIcon");
		theIcon = nil;
	}
	[theApp   registerAnnotation: [eTSlide class] 
							name: "eTSlide"
					RTFDirective: "eTSlide"
					   menuLabel: "Insert Slide Show..."
						 menuKey: '\0'
						menuIcon: (NXImage *) theIcon];
	[theApp registerType:NXCreateFileContentsPboardType("slideshow") 
			for:[eTSlide class]];
	return self;
}

- init
{
	char        buf[MAXPATHLEN];
	NXBundle   *bundle;
	
// PHASE I: Bookkeeping
	[super init];
	counter = -1;
	sprintf(buf, "Untitled Show %d", [NXApp uniqueID]);
	theName = NXUniqueString(buf);
	isLinked = NO;
	bundle = [NXBundle bundleForClass:[eTSlide class]];
	//theImage = [NXImage alloc] init];
	theSound = [[Sound alloc] init];
	icon = theImage = [NXImage findImageNamed:"eTSlideIcon"];
	[theImage setScalable:YES];
	[theImage setDataRetained:YES];
	[theImage setEPSUsedOnResolutionMismatch:YES];
	return self;
}

- initFromPboard:thePboard inDoc:theDoc linked:(BOOL) linked
{
	[self init];
	etDoc = theDoc;
	[etDoc registerNotification:self];
// PHASE II: Parsing out data
	isLinked = linked;
	if (thePboard != nil)
		if ([thePboard findAvailableTypeFrom:&NXFilenamePboardType num:1]) 
		{
			char	*path;
			int		len;

			isLinked = linked;
			[thePboard readType:NXFilenamePboardType data:&path length:&len];
			if (index(path, '\t')) *index(path, '\t')=0;
			//theImage = [theImage initFromFile:path];
			//if ([theImage name])
			//	theName = NXUniqueString([theImage name]);
			//else 
			if (isLinked)
				theName = NXUniqueString(path);
			else theName = NXUniqueString(rindex(path, '/')+1);
			[thePboard deallocatePasteboardData:path length:len];
		}
	return self;
}

- free 
{
	[[NXApp inspector] invalidate]; 
	[etDoc unregisterNotification:self];
	etDoc=nil;
	if (![theImage name] || strcmp([theImage name],"eTSlideIcon")) [theImage free];
	[theSound stop];
	[NXApp delayedFree:theSound];
	return [super free];
}

- calcCellSize:(NXSize *)theSize
{
	if (theImage)[theImage getSize:theSize];
	else [icon getSize:theSize];
	return self;
}

- drawSelf:(const NXRect *)cellFrame inView:controlView
{
	NXPoint	point;
	NXSize	theSize;
	
	if(!etDoc) {  
 		eTextObj = controlView;
		if (!etDoc) etDoc = [eTextObj etDoc];
		[etDoc registerNotification:self];
  	}
  /*
   * the text object expects us not to modify the current graphics state, so
   * we'll save it
   */
    PSgsave();
	
  /* fill our bounds with the text object's background gray (if opaque) */
    if ([controlView isOpaque]) {
	PSsetgray([controlView backgroundGray]);
	NXRectFill(cellFrame);
    }
	
  /* we're in a flipped coordinate system */
    point = cellFrame->origin;
    point.y += cellFrame->size.height;
	
  /* draw the image */
	[theImage getSize:&theSize];
	if ((theSize.width && theSize.height))
	    [theImage composite:NX_SOVER toPoint:&point];
	else [icon composite:NX_SOVER toPoint:&point];
  /* restore the graphics state */
    PSgrestore();
	
    return self;
}

- highlight:(const NXRect *)cellFrame inView:view lit:(BOOL)flag
{
	static int highlighted;
    if (highlighted != flag) {
		highlighted = flag;
      /* toggle highlighting */
		//NXHighlightRect(cellFrame);
    }
    
    return self;
}

- writeComponentToPath:(NXAtom)path inFormat:(int) theFormat
{	
	if (isLinked) return self;
	if (theFormat != ETFD_FORMAT) return self;
	[etDoc registerComponent:NXUniqueString(theName)];
	return self;
}
- readRichText:(NXStream *)stream forView:view 
{
	int	i;
	char buf[MAXPATHLEN];
	
	NXScanf(stream, "%d ", &i);
	if (i != _eTSlideVERSION) {
		// bad version block.
	 NXLogError("eTSlide found unparseable version %d at position %d",
					i, NXTell(stream));
		return nil;
	}
	
	eTextObj = view;
	if (!etDoc) etDoc = [eTextObj etDoc];
	[etDoc registerNotification:self];
	NXScanf(stream, "%c %d ", &isLinked, &i);
	isLinked -= 'A';
	if (i) NXRead(stream, buf, i);
	buf[i] = 0;
	theName = NXUniqueString(buf);
	if (!isLinked && access(buf,F_OK|R_OK)) {
		sprintf(buf, "%s/%s", [[etDoc navinfo] path],theName);
		if (access(buf,F_OK|R_OK)) {
				return self;
		}
	}
	//[theImage initFromFile:buf];
	return self;
}

- writeRichText:(NXStream *)stream forView:view
{
	if(!isLinked)
		NXPrintf(stream, "%d %c %d %s ", _eTSlideVERSION,
			 isLinked ? 'B':'A',strlen(theName), theName);
	return self;
}

- writeASCIIRef:(NXStream *)stream forView:view
{
	NXPrintf(stream, "The slide show animation named %s", theName);
	return self;
}

#define mask (NX_LMOUSEUPMASK|NX_LMOUSEDRAGGEDMASK)
#define Shift(e) (e->flags&(NX_NEXTLSHIFTKEYMASK|NX_NEXTRSHIFTKEYMASK))
#ifndef abs
#define abs(x) (((x)<0)? -(x) : (x))
#endif

int eTSlide_mouseMoved(NXPoint *o, int n) {
	/* true if mouse moves > n pixels from 'o' */
	NXEvent *e;
	NXPoint p;
	float d;
	do {
		e = [NXApp getNextEvent:mask];
		p = e->location;
		d = abs(p.x-o->x);
		if (d < abs(p.y-o->y)) d = abs(p.y-o->y);
	} while (e->type != NX_LMOUSEUP && d<n);
	*o = p;
	return e->type != NX_LMOUSEUP;
}

- (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
{
	if (isLinked)
		return NX_DragOperationLink;
    else return NX_DragOperationAll;
}

- (BOOL) 	trackMouse:(NXEvent *)event
			inRect:(const NXRect *)cellFrame
			ofView:controlView
{
    NXPoint	hitPoint, preHitPoint;
    int		oldMask;
    NXEvent	saveEvent;
    Pasteboard	*dragPasteboard;
	NXPoint mouseLocation;
	
    mouseLocation = event->location;
    [controlView convertPoint:&mouseLocation fromView:NULL];
	oldMask = [[controlView window] eventMask];
    [[controlView window] setEventMask:(oldMask|mask)];
    saveEvent = *event;
    preHitPoint = event->location;
    hitPoint = event->location;

    if (NXPointInRect(&mouseLocation, cellFrame)) {
		if (event->data.mouse.click == 2){
			if ([self respondsTo:@selector(doubleClick:)])
				[self doubleClick:self];
		}
		else if (event->data.mouse.click == 1) {
 		   if (0) { //(eTSlide_mouseMoved(&hitPoint,4)) 
			NXRect	dragRect;
			char	filename[MAXPATHLEN];
			
			[controlView convertPoint: &hitPoint fromView: nil];
			dragRect = *cellFrame;
			dragPasteboard = [Pasteboard newName: NXDragPboard];
		  [dragPasteboard declareTypes:&NXFilenamePboardType num:1 owner:self];
			sprintf(filename, "%s", theName);
			if (access(filename,F_OK|R_OK)) {
				sprintf(filename, "%s/%s", [[etDoc navinfo] path],theName);
			}
			[dragPasteboard writeType: NXFilenamePboardType data: filename
				length: strlen(filename)];
			hitPoint.y += 6;
			preHitPoint.x = 0.0;
			preHitPoint.y = 0.0;
			[controlView
				dragImage:[[Application workspace] getIconForFile:filename]
				at:&(hitPoint) offset:&preHitPoint
				event:&saveEvent pasteboard:dragPasteboard
				source:self slideBack: YES];
    	} else if (event->flags && NX_COMMANDMASK){
			if ([self respondsTo:@selector(commandClick:)])
				[self commandClick:self];
			} else {
				if ([self respondsTo:@selector(click:)])
				[self click:self];
			}
		}
	}
	[[controlView window] setEventMask:oldMask];
	return YES;
}

- resetName:(NXAtom)string
{
	theName = string;
	return self;
}

- resetPath:(NXAtom)newPath
{
	return self;
}

- image {return theImage;}
- (NXAtom) theName {return theName;}
- doc {return etDoc;}
- (BOOL) isLinked {return isLinked;}
- setLinked:(BOOL)l {isLinked=l; return self;}

- click:sender
{
	char buf[MAXPATHLEN];
	// relies on -1 flag value
	if (counter == -1) {
		counter++;
		// load image 0
		sprintf(buf,"%s/%d.tiff", theName, counter);
		if (access(buf, F_OK|R_OK))
			sprintf(buf,"%s/%d.eps", theName, counter);
		if (access(buf, F_OK|R_OK))
			return self;
		[theImage free];
		theImage = [[NXImage alloc] initFromFile:buf];
		[theImage setScalable:YES];
		[theImage setDataRetained:YES];
		[theImage setEPSUsedOnResolutionMismatch:YES];
		[[[etDoc docUI] eTextObj] display];
		
		// play sound 0
		sprintf(buf,"%s/%d.snd", theName, counter);
		if (!access(buf, F_OK|R_OK)){
			[theSound readSoundfile:buf];
			[theSound play];
		}	
	} else {
		// play sound counter
		sprintf(buf,"%s/%d.snd", theName, counter);
		if (!access(buf, F_OK|R_OK)){
			[theSound readSoundfile:buf];
			[theSound play];
		}	

		// load image counter++
		counter++;
		sprintf(buf,"%s/%d.tiff", theName, counter);
		if (access(buf, F_OK|R_OK))
			sprintf(buf,"%s/%d.eps", theName, counter);
		if (access(buf, F_OK|R_OK))
			{counter = -1; return self;}
		[theImage free];
		theImage = [[NXImage alloc] initFromFile:buf];
		[theImage setScalable:YES];
		[theImage setDataRetained:YES];
		[theImage setEPSUsedOnResolutionMismatch:YES];
		[[[etDoc docUI] eTextObj] display];
	}
	return self;
}

- commandClick: sender
{
	char buf[MAXPATHLEN];

	if (counter == 0) return self;
	counter--;
	// load image
	sprintf(buf,"%s/%d.tiff", theName, counter);
	if (access(buf, F_OK|R_OK))
		sprintf(buf,"%s/%d.eps", theName, counter);
	if (access(buf, F_OK|R_OK))
		{return self;}
	[theImage free];
	theImage = [[NXImage alloc] initFromFile:buf];
	[theImage setScalable:YES];
	[theImage setDataRetained:YES];
	[theImage setEPSUsedOnResolutionMismatch:YES];
	[[[etDoc docUI] eTextObj] display];
	// play sound
	sprintf(buf,"%s/%d.snd", theName, counter);
	if (!access(buf, F_OK|R_OK)){
		[theSound readSoundfile:buf];
		[theSound play];
	}	
	return self;
}

@end